package cn.anzhiyublog.staranimegallery.service.impl;

import cn.anzhiyublog.staranimegallery.exception.GalleryException;
import cn.anzhiyublog.staranimegallery.mapper.SpaceMapper;
import cn.anzhiyublog.staranimegallery.model.domain.Space;
import cn.anzhiyublog.staranimegallery.model.domain.User;
import cn.anzhiyublog.staranimegallery.model.dto.space.*;
import cn.anzhiyublog.staranimegallery.model.enums.Authority;
import cn.anzhiyublog.staranimegallery.model.enums.Role;
import cn.anzhiyublog.staranimegallery.model.enums.SpaceLevel;
import cn.anzhiyublog.staranimegallery.model.enums.StatusCode;
import cn.anzhiyublog.staranimegallery.model.vo.SpaceOnlyIdAndNameVO;
import cn.anzhiyublog.staranimegallery.model.vo.SpaceVO;
import cn.anzhiyublog.staranimegallery.service.SpaceService;
import cn.anzhiyublog.staranimegallery.util.ThrowUtils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 空间业务层
 *
 * @author 安知一只鱼
 */
@Service
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceService {
    @Autowired
    private SpaceMapper spaceMapper;

    private final Map<Long,Object> lockmap = new ConcurrentHashMap<>();

    @Override
    public long createSpace(SpaceCreateRequest spaceCreateRequest, User loginUser) {
        // 实体转换
        Space space = new Space();
        BeanUtil.copyProperties(spaceCreateRequest,space);
        space.setUserId(loginUser.getId());
        // 设置空间容量，普通用户默认为普通空间，管理员默认为专业空间
        Role role = Role.getEnumByCode(loginUser.getRole());
        if (Authority.inManage(role)) {
            space.setSpaceLevel(SpaceLevel.PROFESSIONAL.getLevel());
        }else if (Authority.inGeneral(role)){
            space.setSpaceLevel(SpaceLevel.NORMAL.getLevel());
        }else {
            throw new GalleryException(StatusCode.BAD_REQUEST,"用户角色异常");
        }
        this.fillSpaceByLevel(space);
        // 数据校验
        this.validSpace(space,true);
        // 加锁保存
        Long userId = loginUser.getId();
        Object lock = lockmap.computeIfAbsent(userId, key -> new Object());
        synchronized (lock){
            try {
                // 校验该用户是否已经有空间
                LambdaQueryWrapper<Space> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Space::getUserId, loginUser.getId());
                boolean isExist = this.baseMapper.exists(queryWrapper);
                ThrowUtils.throwIf(isExist, StatusCode.CONFLICT, "用户空间已达上限");
                // 执行创建
                boolean isSave = this.save(space);
                ThrowUtils.throwIf(!isSave, StatusCode.INTERNAL_SERVER_ERROR, "创建失败");
                return space.getId();
            }finally {
                // 是否资源，防止内存泄露
                lockmap.remove(userId);
            }
        }
    }

    @Override
    public void deleteSpace(SpaceDeleteRequest spaceDeleteRequest, User loginUser) {
        // 请求 => 实体
        Space space = new Space();
        BeanUtil.copyProperties(spaceDeleteRequest,space);
        // 是否为本人或管理员
        boolean isSelfOrManage = this.isSelfOrManage(loginUser,space.getId());
        ThrowUtils.throwIf(!isSelfOrManage, StatusCode.FORBIDDEN);
        // 执行删除
        boolean isDelete = this.removeById(space.getId());
        ThrowUtils.throwIf(!isDelete, StatusCode.INTERNAL_SERVER_ERROR, "删除失败");
    }

    @Override
    public void updateSpace(SpaceUpdateRequest spaceUpdateRequest) {
        Space space = new Space();
        BeanUtil.copyProperties(spaceUpdateRequest,space);
        // 自动修改数据
        this.fillSpaceByLevel(space);
        // 数据校验
        this.validSpace(space,false);
        // 空间存在校验
        LambdaQueryWrapper<Space> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Space::getId,space.getId());
        boolean isExist = this.baseMapper.exists(queryWrapper);
        ThrowUtils.throwIf(!isExist, StatusCode.NOT_FOUND, "空间不存在");
        // 执行修改
        boolean isUpdate = this.updateById(space);
        ThrowUtils.throwIf(!isUpdate, StatusCode.INTERNAL_SERVER_ERROR, "修改失败");
    }

    @Override
    public void editSpace(SpaceEditRequest spaceEditRequest, User loginUser) {
        // 转换实体
        Space space = new Space();
        BeanUtil.copyProperties(spaceEditRequest,space);
        // 本人校验
        boolean isSelf = this.isSelf(loginUser,space.getId());
        ThrowUtils.throwIf(!isSelf, StatusCode.FORBIDDEN);
        // 参数校验
        this.validSpace(space,false);
        // 执行修改
        boolean isUpdate = this.updateById(space);
        ThrowUtils.throwIf(!isUpdate, StatusCode.INTERNAL_SERVER_ERROR, "修改失败");
    }

    @Override
    public Space getSpaceById(long spaceID) {
        Space space = this.getById(spaceID);
        ThrowUtils.throwIf(space==null,StatusCode.NOT_FOUND,"空间不存在");
        return space;
    }

    @Override
    public Page<Space> listSpaceByPage(SpacePageQueryRequest spacePageQueryRequest) {


        // 参数校验: 当前页数不能小于等于0
        ThrowUtils.throwIf(spacePageQueryRequest.getCurrent()<=0,StatusCode.BAD_REQUEST,"当前页数不能小于等于0");
        // 构造分页请求
        LambdaQueryWrapper<Space> queryWrapper = new LambdaQueryWrapper<>();
        // id 精准查询
        queryWrapper.eq(ObjectUtil.isNotNull(spacePageQueryRequest.getId()),
                Space::getId,spacePageQueryRequest.getId());
        // 空间名称 模糊查询
        queryWrapper.like(StrUtil.isNotBlank(spacePageQueryRequest.getSpaceName()),
                Space::getSpaceName,spacePageQueryRequest.getSpaceName());
        // 空间等级 精准查询
        queryWrapper.eq(ObjectUtil.isNotNull(spacePageQueryRequest.getSpaceLevel()),
                Space::getSpaceLevel,spacePageQueryRequest.getSpaceLevel());
        // 用户id 精准查询
        queryWrapper.eq(ObjectUtil.isNotNull(spacePageQueryRequest.getUserId()),
                Space::getUserId,spacePageQueryRequest.getUserId());
        // 执行分页查询
        return this.page(new Page<>(spacePageQueryRequest.getCurrent(),
                spacePageQueryRequest.getSize()), queryWrapper);

    }

    @Override
    public SpaceVO ObjToVO(Space space) {
        SpaceVO spaceVO = new SpaceVO();
        BeanUtil.copyProperties(space,spaceVO);
        return spaceVO;
    }

    @Override
    public List<SpaceVO> ObjToVO(List<Space> spaces) {
        return spaces.stream().map(this::ObjToVO).collect(Collectors.toList());
    }

    @Override
    public List<SpaceOnlyIdAndNameVO> listMySpaceOnlyIdAndNameVO(User loginUser) {
        List<Space> spaces = this.lambdaQuery()
                .eq(Space::getUserId, loginUser.getId())
                .list();
        List<SpaceOnlyIdAndNameVO> result = new ArrayList<>();
        for (Space space: spaces){
            SpaceOnlyIdAndNameVO vo = new SpaceOnlyIdAndNameVO();
            BeanUtil.copyProperties(space,vo);
            result.add(vo);
        }
        return result;
    }

    /**
     * 根据级别自动填充
     */
    private void fillSpaceByLevel(Space space) {
        // 根据级别自动填充
        SpaceLevel spaceLevel = SpaceLevel.getEnumByLevel(space.getSpaceLevel());
        if (spaceLevel!=null){
            // 获取该级别下最大容量和最大个数
            long maxCapacity = spaceLevel.getMaxCapacity();
            long maxCount = spaceLevel.getMaxCount();
            // 填充进space对象中,如果space中有就不用填充了（定制）
            if (space.getMaxCapacity()==null)
                space.setMaxCapacity(maxCapacity);
            if (space.getMaxCount()==null)
                space.setMaxCount(maxCount);
        }
        // 名字没填就设置默认值
        if (space.getSpaceName()==null){
            space.setSpaceName("未知星云");
        }
    }

    /**
     * 数据校验
     */
    private void validSpace(Space space, boolean isCreate){
        // 空校验
        ThrowUtils.throwIf(space==null, StatusCode.BAD_REQUEST, "空间信息不可为空");
        // 创建的情况下名称和级别不能为空
        if (isCreate){
            ThrowUtils.throwIf(space.getSpaceName() == null || space.getSpaceLevel() == null,
                    StatusCode.BAD_REQUEST,
                    "空间名称和级别不可为空");
        }
        // 若需要修改级别则检查级别是否存在
        ThrowUtils.throwIf(space.getSpaceLevel() != null && SpaceLevel.getEnumByLevel(space.getSpaceLevel()) == null,
                StatusCode.BAD_REQUEST,
                "空间级别不存在");
        // 名称长度校验
        final int MAX_LENGTH = 32;
        ThrowUtils.throwIf(space.getSpaceName().length() > MAX_LENGTH,
                StatusCode.BAD_REQUEST,
                "空间名称过长");
    }

    /**
     * 判断是否是本人
     */
    private boolean isSelf(User loginUser, long spaceId){
        Long userId = spaceMapper.getUserIdBySpaceId(spaceId);
        ThrowUtils.throwIf(userId==null,StatusCode.NOT_FOUND,"空间不存在");
        return userId.equals(loginUser.getId());
    }

    /**
     * 判断是否是本人或管理员
     */
    private boolean isSelfOrManage(User loginUser, long spaceId){
        boolean isSelf = this.isSelf(loginUser, spaceId);
        Role role = Role.getEnumByCode(loginUser.getRole());
        boolean isManage = Authority.inManage(role);
        return isSelf || isManage;
    }
}
